home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-12-11 | 59.9 KB | 1,978 lines | [TEXT/MPS ] |
- /*
- File: Link.cpp
-
- Contains: Link Classes Implementation
-
- Written by: Mike Halpin
-
- Copyright: © 1995 by Apple Computer, Inc., all rights reserved.
- */
-
- // -- DrawEditor Includes --
-
- #ifndef _COMPILERDEFS_
- #include "CompDefs.h"
- #endif
-
- // -- DrawEditor Includes --
-
- #ifndef _LINK_
- #include "Link.h"
- #endif
-
- #ifndef _DRAWEDITOR_
- #include "DrawEditor.h"
- #endif
-
- #ifndef _SELECTION_
- #include "Selection.h"
- #endif
-
- #ifndef _SHAPES_
- #include "Shapes.h"
- #endif
-
- #ifndef _DRAWEDITORUTILS_
- #include "DrawEditorUtils.h"
- #endif
-
- #ifndef _PROMISE_
- #include "Promise.h"
- #endif
-
- #ifndef _LINKCOMMANDS_
- #include "LinkCommands.h"
- #endif
-
- // -- OpenDoc Includes --
-
- #ifndef SOM_Module_OpenDoc_StdProps_defined
- #include <StdProps.xh>
- #endif
-
- #ifndef SOM_Module_OpenDoc_StdTypes_defined
- #include <StdTypes.xh>
- #endif
-
- #ifndef SOM_ODStorageUnit_xh
- #include <StorageU.xh>
- #endif
-
- #ifndef SOM_ODLink_xh
- #include <Link.xh>
- #endif
-
- #ifndef SOM_ODLinkSpec_xh
- #include <LinkSpec.xh>
- #endif
-
- #ifndef SOM_ODLinkSource_xh
- #include <LinkSrc.xh>
- #endif
-
- // -- OpenDoc Utilities --
-
- #ifndef _ODUTILS_
- #include "ODUtils.h"
- #endif
-
- #ifndef _STORUTIL_
- #include "StorUtil.h"
- #endif
-
- #ifndef _ODMEMORY_
- #include "ODMemory.h" // ODDisposePtr
- #endif
-
- #ifndef _ODDEBUG_
- #include "ODDebug.h"
- #endif
-
- #ifndef _UTILERRS_
- #include "UtilErrs.h"
- #endif
-
- #ifndef _TEMPITER_
- #include "TempIter.h"
- #endif
-
- // -- Toolbox Includes --
-
- #ifndef mathRoutinesIncludes
- #include <math routines.h>
- #endif
-
- #ifndef __MEMORY__
- #include <memory.h>
- #endif
-
-
- //=============================================================================
- // class CPublishLink
- //=============================================================================
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::CPublishLink
- //
- // Description: This constructor is called from a CCutCopyShapeCommand or a
- // CDragShapeCommand. The commands pass in a list of unsubscribed shapes and a
- // list of CSubscribeLink's. The CSubscribeLink's provide the as yet unpublished
- // link with safe access to the contained subscribed shapes, in the event that
- // those shapes are replaced during an update before publishing occurs.
- //---------------------------------------------------------------------------------------
-
- CPublishLink::CPublishLink( ODUpdateID updateID,
- CSelection* selection,
- COrderedList* shapeList,
- COrderedList* subscribeLinks)
- {
- fODLinkSource = kODNULL;
- fODID = kODNULL;
-
- fUpdateID = updateID;
- fPendingID = updateID;
-
- fSelection = selection;
- fDrawEditor = selection->GetDrawEditor();
-
- fWasRemoved = kODFalse;
- fPublished = kODFalse;
- fNewlyPublished = kODFalse;
-
- fSelectedCount = 0;
- fPromise = kODNULL;
- fPublishContent = kODNULL;
-
- fShapeList = shapeList;
- fSubscribeLinks = subscribeLinks;
-
- fHasCommandOutstanding = kODFalse;
-
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::CPublishLink
- //
- // Description: This constructor is called by the selection's content object when it
- // finds a link to internalize. This does not initialize any real data because that will
- // be done in InternalizeLink and PostCloneInternalizeLink.
- //---------------------------------------------------------------------------------------
-
- CPublishLink::CPublishLink(CSelection* selection)
- {
-
- fODLinkSource = kODNULL;
- fODID = kODNULL;
-
- fUpdateID = kODNULL;
- fPendingID = kODNULL;
-
- fSelection = selection;
- fDrawEditor = selection->GetDrawEditor();
-
- fWasRemoved = kODFalse;
- fPublished = kODFalse;
- fNewlyPublished = kODFalse;
-
- fSelectedCount = 0;
- fPromise = kODNULL;
-
- fShapeList = new COrderedList;
- fSubscribeLinks = new COrderedList;
- fPublishContent = kODNULL;
-
- fHasCommandOutstanding = kODFalse;
- }
-
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::~CPublishLink
- //---------------------------------------------------------------------------------------
-
- CPublishLink::~CPublishLink()
- {
- ODSafeReleaseObject(fODLinkSource);
-
- // Here's why we don't need to 'Unpublish' our shapes and contained subscribe links:
-
- // A. When deleted because it failed to be internalize after cloning, then CShape::Publish was not called, so
- // there are no references.
- // B. When called due to commiting a removal of a link, all the contained objects are being commited
- // out of existance as well, so who cares
- // C. When called due to commiting the Breaking of the link, then each contained object had to be 'Unpublished'
- // when the link was broken.
-
- // If we were ever published, fShapeList & fPublishContent are owned by fPromise so just delete the promise,
-
- if (fPromise)
- delete fPromise;
- else
- delete fShapeList;
-
- delete fSubscribeLinks;
-
-
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::Publish
- //
- // Description: This is called from CreateLink when the link has not been published.
- // Also used for 'Undo Break Link Source'. It establishes referneces to this object
- // in each contained CShape and CSubscribe link.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::Publish(Environment* ev)
- {
- // In it's published state, a CPublishLink just contains a list of all it's shapes. That's what
- // CDrawContent::Externalize knows how to deal with. In that state, any included CSubscribeLink objects
- // can dynamically replace shapes in the publisher during link updates, because the CSubscribeLink contains
- // a pointer to each containing publisher
-
- // However, here in the pre-published (pending) or unpublished (broken) state, our content, including
- // contained subscribers do not contain a reference to the this object. In this state, we have a list
- // only of unsubscribed shapes and a list of CSubscribeLink's. Publishing converts that format into
- // a list of shapes (sutibalbe for externalzing when we update the ODLinkSource object), while
- // adding the necessary references to this object to each CShape and each CSubscribeLink.
-
- // This is one of several areas that could be simplified if CSubscribeLink was derived from CShape.
- // and no attempt was made to maintain other direct references to any subscribed content.
-
- if (!fPublished)
- {
- fPublished = kODTrue;
-
- // The first time we get published, we need to create an ODLinkSource.
- if (!fODLinkSource)
- {
- fODLinkSource = fDrawEditor->GetDraft(ev)->CreateLinkSource(ev, fDrawEditor->GetODPart());
- fNewlyPublished = kODTrue; // true until first update completes.
- }
-
- COrdListIterator shapeIter(fShapeList);
- for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
- {
- if (shape->IsSelected())
- fSelectedCount++;
-
- shape->Publish(ev, this);
-
- }
-
- // CSubscribeLink::Publish, besides establishing a reference to this, adds each subscribed shape
- // to our shape list so that we have a simple list of shapes for externalizing when we update the
- // link source.
-
- while (fSubscribeLinks->Count() != 0)
- {
- CSubscribeLink* sLink = (CSubscribeLink*)fSubscribeLinks->RemoveFirst();
- sLink->Publish(ev, this);
- }
-
- ASSERT(fShapeList->Count() != 0, kODErrAssertionFailed);
-
- if (fSelectedCount == fShapeList->Count())
- fSelection->AddPublishLink(this);
-
-
- // There's no need to create a new link promise with the same content every time
- // we externalize. This constructor just copies fShapeList reference, not the list itself,
- // so changes to fShapeList are automatically reflected in the promise's content.
-
- if (!fPromise)
- {
- fPromise = new CPromise(fDrawEditor, fDrawEditor->GetFirstSourceFrame(ev), fShapeList, kODCloneToLink);
- fPublishContent = fPromise->GetPromiseContent();
- }
-
- // Add the link to the part's content.
- this->AddToPart(ev);
- }
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::PostCloneInternalizeLink
- //
- // Description: Internalize the ODLinkSource from the storage ID read in
- // in InternalizeLink. If successful, wire up any contained shapes and any
- // contained subscribe links so that the are 'Published' by this link source.
- // This is equivalent of Publish in its result, only starting from a different
- // state.
- //---------------------------------------------------------------------------------------
-
- ODBoolean CPublishLink::PostCloneInternalizeLink(Environment* ev, ODDraft* toDraft, CShape* shape)
- {
- ODBoolean result = kODTrue;
-
- // for the case of a single embedded part, a shape object was not created until
- // after cloning was done, so we had to defer attatching it to any links.
-
- if (shape)
- {
- this->AddShape(shape);
- }
-
- if (fODLinkSource == kODNULL)
- {
- result = toDraft->IsValidID(ev, fODID);
-
- if (result)
- fODLinkSource = toDraft->AcquireLinkSource(ev, fODID);
- }
-
- // This is a lot like Publish, but doesn't have the advantage of a ready made
- // list of subscribe links and a filtered list of shapes to start with.
- if (result)
- {
- COrderedList tempList;
-
- COrdListIterator shapeIter(fShapeList);
- for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
- {
- // When the shapes were added, they were not yet part of the selection, even if it was
- // the Selection content that was internalizing. If the shapes were added to the selection
- // then it was before they pointed to this publish link. The link itself is already in
- // the appropriate content list, so we just need to update fSelectedCount
-
- if (shape->IsSelected())
- ++fSelectedCount;
-
- CSubscribeLink* sLink = shape->GetSubscribeLink();
-
- if (!sLink)
- shape->Publish(ev, this);
- else
- {
- tempList.Remove(sLink); // does nothing if not already there
- tempList.AddFirst(sLink); // makes removal efficient when consecutive shapes have same subscriber
- }
- }
-
- while(tempList.Count() != 0)
- {
- CSubscribeLink* sLink = (CSubscribeLink*)tempList.RemoveFirst();
- sLink->GetPublishLinks()->AddLast(this);
- }
-
- fPromise = new CPromise(fDrawEditor, fDrawEditor->GetFirstSourceFrame(ev), fShapeList, kODCloneToLink);
- fPublishContent = fPromise->GetPromiseContent();
- fPublished = kODTrue;
-
- }
-
- return result;
-
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::Unpublish
- //
- // Description: Convert the content model from a list of shapes to a list of non-subscribed
- // shapes and a list of CSubscribeLink's. Unpublish everything and remove the link from
- // the part's content model.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::Unpublish(Environment* ev)
- {
-
- if (fPublished)
- {
- CShape* shape;
-
- // before we mess anything up, we need to see if this link is part of
- // a clipboard promise. This would be true iff all our content is
- // in a clipboard promise.
-
- ODBoolean promised = kODTrue;
-
- COrdListIterator ite(fShapeList);
- for (shape = (CShape*)ite.First(); ite.IsNotComplete(); shape = (CShape*)ite.Next())
- {
- if (!shape->IsPromisedToClipboard())
- {
- promised = kODFalse;
- break;
- }
- }
-
- if (promised)
- ::ResolveClipboardPromises(ev, fDrawEditor->GetSession(ev));
-
-
- fPublished = kODFalse;
-
- this->RemoveFromPart(ev);
-
- // This stuff won't be maintained while the link is broken. It'll be restored
- // to the current state if and when this is undone.
-
- if (fSelectedCount == fShapeList->Count())
- fSelection->RemovePublishLink(this);
-
- fSelectedCount = 0;
-
- // This restores the content to the format expected by Publish so that this action
- // can be undone. This format replaces any shapes that are subscribed with references
- // to the CSubscribeLink object. That protects us from having dangling shape references in
- // the event that the subscribe link updates while it is not 'Published' by this CPublishLink.
-
- CShape* newFirstShape = kODNULL;
-
- while ((shape = (CShape*)fShapeList->First()) != newFirstShape)
- {
- fShapeList->RemoveFirst();
- CSubscribeLink* sLink = (CSubscribeLink*)shape->GetSubscribeLink();
- if (!sLink)
- {
- shape->Unpublish(ev, this); // Remove shape's pointer to this publisher
- fShapeList->AddLast(shape); // Put shape back on the end of our shape list
- if(!newFirstShape)
- newFirstShape = shape; // So we'll know when to stop
- }
- else
- {
- fSubscribeLinks->Remove(sLink); // prevents duplicates, does nothting unless sLink is already there
- fSubscribeLinks->AddFirst(sLink);
- }
-
- }
-
- COrdListIterator linkIter(fSubscribeLinks);
- for (CSubscribeLink* sLink = (CSubscribeLink*)linkIter.First(); linkIter.IsNotComplete(); sLink = (CSubscribeLink*)linkIter.Next())
- {
- sLink->Unpublish(ev, this);
- }
-
- // Since we'll no longer be informed of shapes being selected clear the count
- // it will be recalculated correctly if and when we are republished.
- fSelectedCount = 0;
- }
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::AddToPart
- //
- // Description: Add the link to the par't content model, and set the ODLinkSource's
- // part.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::AddToPart(Environment* ev)
- {
- fDrawEditor->AddPublishLink(this);
- this->SetSourcePart(ev);
-
- fWasRemoved = kODFalse;
- }
-
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::RemoveFromPart
- //
- // Description: Remove the link from the par't content model, and clear the ODLinkSource's
- // part.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::RemoveFromPart(Environment *ev)
- {
-
- fDrawEditor->RemovePublishLink(ev, this);
- fODLinkSource->SetSourcePart(ev, kODNULL);
-
- fWasRemoved = kODTrue;
- }
-
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::SetSourcePart
- //
- // Description: Set's the ODLinkSource's 'owning' part.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::SetSourcePart(Environment* ev)
- {
- fODLinkSource->SetSourcePart(ev, fDrawEditor->GetODPart()->GetStorageUnit(ev));
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::ContentUpdated
- //
- // Description: This updates the ODLinkSourceObject if appropriate.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::ContentUpdated(Environment* ev, ODUpdateID updateID, ODBoolean forceUpdate)
- {
-
- // special case, only from create link when new destination is being established
- // to an already functioning link. This case is actually only relevant if
- // promises for multiple representations are written. Otherwise, we don't actually
- // need to anything in that case.
-
- ODBoolean justRewrite = forceUpdate && (updateID == kODUnknownUpdate)
- && (fUpdateID == fODLinkSource->GetUpdateID(ev));
-
- // replace a null id with the current id. In the justRewrite case, using the
- // old id prevents unecessary destination updates from occuring.
- updateID = updateID ? updateID : fUpdateID;
-
-
- if(forceUpdate || fODLinkSource->IsAutoUpdate(ev))
- {
- ODLinkKey key;
-
- if (fODLinkSource->Lock(ev, 0, &key))
- {
-
- TRY
- fODLinkSource->Clear(ev, updateID, key);
-
- ODStorageUnit* linkSU = fODLinkSource->GetContentStorageUnit(ev, key);
-
- this->ExternalizeLinkContent(ev, linkSU);
-
- // Calling ContentUpated insures that link cycle protection is excersized.
- // Not calling it when we're just rewriting promises (ie our content hasn't changed)
- // allows us to re-use the old update id without triggering the link cycle dialog.
- if (!justRewrite)
- fODLinkSource->ContentUpdated(ev, updateID, key);
-
- CATCH_ALL
-
- fODLinkSource->Clear(ev, fUpdateID, key);
- fODLinkSource->Unlock(ev, key);
-
- if (fNewlyPublished)
- {
- this->Unpublish(ev);
- fODLinkSource->Release(ev);
- fODLinkSource = kODNULL;
- fNewlyPublished = kODFalse;
- }
-
- RERAISE;
-
- ENDTRY
-
- fODLinkSource->Unlock(ev, key);
- fNewlyPublished = kODFalse;
- }
-
- }
-
- fUpdateID = updateID;
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::ExternalizeLinkContent
- //
- // Description: Write the source content or a promise out to the links storage unit
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::ExternalizeLinkContent(Environment* ev, ODStorageUnit* linkSU)
- {
-
- ODDraft* fromDraft = fDrawEditor->GetDraft(ev);
- ODDraft* dstDraft = linkSU->GetDraft(ev);
-
- // Create clone info
- CCloneInfo info(0, fromDraft, fDrawEditor->GetFirstSourceFrame(ev), kODCloneToLink);
-
- // Either write a promise, or externalize a single embedded frame
- CEmbeddingShape* tShape = fPublishContent->IsOneEmbeddedShape(ev);
- if (tShape)
- {
- ODFrame* embeddedFrame = tShape->
- GetEmbeddedFacet(ev, fDrawEditor->GetFirstSourceFrame(ev))->GetFrame(ev);
-
- fPublishContent->ExternalizeSingleEmbeddedFrame( ev,
- linkSU,
- &info,
- embeddedFrame);
- }
- else
- {
- // Focus to the content property
- ODSUForceFocus(ev, linkSU, kODPropContents, kDrawEditorKind);
-
- // There's no real gain in writing promises to links unless
- // there are multiple representations. This is just a demonstration.
-
- fPromise->Promise(ev, linkSU);
- }
-
- }
-
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::AddShape
- //
- // Description: Add a shape to the source content.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::AddShape(CShape* shape)
- {
- // A CPublishLink which was entirely removed, never had any shapes removed from it
- // so that it could still fulfill a promise in the case that the removal was from a cut,
- // so we don't do anything in that case.
-
- if (!fWasRemoved)
- {
- fShapeList->AddLast(shape);
- if (shape->IsSelected())
- fSelectedCount++;
- }
- }
-
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::AddShape
- //
- // Description: Add and publish a shape.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::AddShape(Environment* ev, CShape* shape)
- {
- // Note that this does nothing if the shape is a subscriber. In that case any publishing
- // related behavior is managed by it's subscribe link.
-
- shape->Publish(ev, this);
-
- this->AddShape(shape);
- }
-
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::RemoveShape
- //
- // Description: Remove a shape from the source content
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::RemoveShape(CShape *shape)
- {
- //(MH) A CPublishLink which is entirely removed, does not have any shapes removed from it
- // so that it can still fulfill a promise in the case that the removal was from a cut.
- // so we don't do anything in that case.
-
- if (!fWasRemoved)
- {
- // Shapes are only removed from here when being removed from the content model, we allow the shape
- // to continue pointing to the publisher, so it can be replaced when added back to the content
- // if the action is reversed.
-
- fShapeList->Remove(shape);
- if (shape->IsSelected())
- fSelectedCount--;
- }
- }
-
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::ShapeSelected
- //
- // Description: As shapes are selected and unselected, they inform any links they are
- // involved in. By keeping track of how many of this links shapes are
- // selected we can tell efficiently when the link itself should be added
- // and removed from the selection. Only a fully selected link is extenalized
- // during as part of the selection.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::ShapeSelected(ODBoolean selectState)
- {
- short oldCount = fSelectedCount;
-
- if (selectState)
- {
- ++fSelectedCount;
- ASSERT_NOT_NULL(fSelectedCount <= fShapeList->Count());
-
- if (fSelectedCount == fShapeList->Count())
- {
- fSelection->AddPublishLink(this);
- }
- }
- else
- {
- --fSelectedCount;
- ASSERT_NOT_NULL(fSelectedCount >= 0);
-
- if (oldCount == fShapeList->Count())
- {
- fSelection->RemovePublishLink(this);
- }
-
- }
-
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::Count
- //
- // Description: How many shapes in the source content
- //---------------------------------------------------------------------------------------
-
- ODULong CPublishLink::Count()
- {
- return fShapeList->Count();
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::ExternalizeLink
- //
- // Description: Write out our private format for externalizing a link source.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::ExternalizeLink(Environment *ev, ODStorageUnit* su, CCloneInfo* cloneInfo)
- {
- ODID linkSourceID = this->GetODLinkSource()->GetID(ev);
- ODBoolean valid = kODTrue;
-
- if (cloneInfo)
- {
- linkSourceID = cloneInfo->fFromDraft->Clone(ev, cloneInfo->fKey, linkSourceID , kODNULLID, kODNULLID);
- valid = cloneInfo->fFromDraft->IsValidID(ev, linkSourceID);
- }
-
- if (valid)
- {
- // store the number of shapes. This first, because we use 0 shape count as
- // tag for an invalid source link.
- ODUShort shapeCnt = fShapeList->Count();
-
- StorageUnitSetValue(su, ev, sizeof(ODUShort), &shapeCnt);
-
- // store a reference to the link
- ODStorageUnitRef aSURef ;
- su->GetStrongStorageUnitRef(ev, linkSourceID, aSURef);
- StorageUnitSetValue(su, ev, kODStorageUnitRefSize, &aSURef);
-
- // store the current update id
-
- StorageUnitSetValue(su, ev, sizeof(ODUpdateID), &fUpdateID);
-
- // store the export indices for each shape in the link.
- COrdListIterator iter(fShapeList);
- for (CShape *shape = (CShape*)iter.First(); iter.IsNotComplete(); shape = (CShape*)iter.Next())
- {
- ODUShort extInd = shape->GetExternalizationIndex();
- StorageUnitSetValue(su, ev, sizeof(ODUShort), &extInd);
- }
- }
- else
- {
- ODUShort invalShapeCnt = 0;
- StorageUnitSetValue(su, ev, sizeof(ODUShort), &invalShapeCnt);
- }
-
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::InternalizeLink
- //
- // Description: Read in our private representation of a link source.
- //---------------------------------------------------------------------------------------
-
- ODBoolean CPublishLink::InternalizeLink( Environment *ev, ODStorageUnit *su, CCloneInfo *cloneInfo, CShape** shapeTable)
- {
- ODUShort count;
- StorageUnitGetValue(su, ev, sizeof(ODUShort), &count);
-
- if (count == 0) // link was invalid from the git go
- return kODFalse;
-
- ODBoolean validLink = kODTrue;
- ODVolatile(validLink);
-
- TRY
-
- ODStorageUnitRef aSURef;
- StorageUnitGetValue(su, ev, kODStorageUnitRefSize, &aSURef);
-
- validLink = su->IsValidStorageUnitRef(ev, aSURef) ;
-
- StorageUnitGetValue(su, ev, sizeof(ODUpdateID), &fUpdateID);
-
- if (validLink )
- {
- // we have a validated su ref for the link, so clone and get the link
- fODID = su->GetIDFromStorageUnitRef(ev, aSURef);
-
- if (cloneInfo)
- fODID = cloneInfo->fFromDraft->Clone(ev, cloneInfo->fKey, fODID, kODNULLID, kODNULLID);
- }
-
- for (ODUShort k = 0; k < count; k++)
- {
- ODUShort intIndex;
- StorageUnitGetValue(su, ev, sizeof(short), &intIndex);
-
- if(validLink && (shapeTable != kODNULL))
- {
- CShape* shape = shapeTable[intIndex];
- this->AddShape(shape);
- }
- }
-
- CATCH_ALL
- validLink = kODFalse;
- ENDTRY
-
- return validLink;
- }
-
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::ShowLinkInfoDialog
- //
- // Description: Post the Link Source Info dialog and handle the results.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::ShowLinkInfoDialog(Environment* ev)
- {
-
- ODLinkInfoResult infoResult;
- ODLinkSource *linkSource = this->GetODLinkSource();
-
- // Get a facet to pass to ShowLinkSourceInfo
- TempODFrameFacetIterator facets(ev,fDrawEditor->GetFirstSourceFrame(ev));
-
- if ( linkSource->ShowLinkSourceInfo(ev,
- facets.Current(),
- this->GetUpdateID(),
- !fDrawEditor->IsReadOnly(),
- &infoResult) )
- {
- switch (infoResult.action)
- {
- case kODLinkInfoBreakLink:
- CBreakLinkSourceCommand* command = new CBreakLinkSourceCommand(fDrawEditor, this);
- fDrawEditor->ExecuteCommand(ev, command);
- break;
- case kODLinkInfoUpdateNow:
-
- // a manual update is always with a new update id. kODTrue = force an update.
- this->ContentUpdated(ev, fDrawEditor->GetSession(ev)->UniqueUpdateID(ev), kODTrue);
- break;
-
- case kODLinkInfoOk:
- if (infoResult.autoUpdate != linkSource->IsAutoUpdate(ev))
- {
- linkSource->SetAutoUpdate(ev, infoResult.autoUpdate);
-
- if (infoResult.autoUpdate && (this->GetUpdateID() != linkSource->GetUpdateID(ev)))
- this->ContentUpdated(ev, this->GetUpdateID());
-
- }
- break;
- default:
- break;
- }
- }
- }
-
- //---------------------------------------------------------------------------------------
- // CPublishLink::RevealLink
- //
- // Description: Select the link's content. Assumes that the Document has already been
- // brought to the front, and the part activated.
- //---------------------------------------------------------------------------------------
-
- void CPublishLink::RevealLink(Environment* ev)
- {
- // until we have a special way of revealing a link just select it.
-
- fSelection->CloseSelection(ev);
-
- COrdListIterator iter(fShapeList);
- for (CShape* shape = (CShape*)iter.First(); iter.IsNotComplete(); shape = (CShape*)iter.Next())
- {
- fSelection->AddToSelection(ev, shape, kODTrue);
- }
- }
-
- //=============================================================================
- // class CSubscribeLink
- //=============================================================================
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::CSubscribeLink
- //
- // Description: This constructor is used when creating the object due to
- // a paste as result indicating that a link is to be created.
- //-----------------------------------------------------------------------------
-
- CSubscribeLink::CSubscribeLink(ODLink* odLink, CSelection* selection,
- ODLinkInfo& linkInfo, ODPasteAsResult& paResult, ODBoolean defaultIsMerge)
- {
- fODLink = odLink; // It was acquired by the caller
- fODID = kODNULL; // used when internalizing a link from storage
-
- fDrawEditor = selection->GetDrawEditor();
-
- // Copy link info
- fLinkInfo = linkInfo;
- fPasteAsResult = paResult;
- fDefaultIsMerge = defaultIsMerge;
-
- fPublishLinks = new COrderedList;
-
- fSelection = selection;
- fSelectedCount = 0;
- fRegistered = kODFalse;
- fWasRemoved = kODFalse;
- fRemovedShapes = kODFalse;
-
- fShapeList = new COrderedList;
-
- fSubscribeContent = new CSubscribeContent(fDrawEditor, fShapeList, this);
-
- fCommand = kODNULL;
-
- fOriginPoint.x = 50; // Default position for first update.
- fOriginPoint.y = 50;
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::CSubscribeLink
- //
- // Description: This constructor is called when creating a link object while
- // internalizing.Additional values are initialized in the InternalizeLink method
- //-----------------------------------------------------------------------------
-
- CSubscribeLink::CSubscribeLink(CSelection* selection)
- {
- // Theoretically, the constructor could do the internalization to ensure
- // complete initialization, and allow failures to throw back to the caller (CDrawContent::InitializeSubLinks)
- // to catch. Currently, InternalizeLink is called immediately after this constructor, and catches failures
- // itself, returning kODFalse for a failure.
-
- fODLink = kODNULL;
- fODID = kODNULL; // used when internalizing a link from storage
-
- fDrawEditor = selection->GetDrawEditor();
-
- fPublishLinks = new COrderedList;
-
- fSelection = selection;
- fSelectedCount = 0;
- fRegistered = kODFalse;
- fWasRemoved = kODFalse;
- fRemovedShapes = kODFalse;
-
- fShapeList = new COrderedList;
-
- fSubscribeContent = new CSubscribeContent(fDrawEditor, fShapeList, this);
-
- fCommand = kODNULL;
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::~CSubscribeLink
- //-----------------------------------------------------------------------------
-
- CSubscribeLink::~CSubscribeLink()
- {
- ODSafeReleaseObject(fODLink);
-
- delete fPublishLinks;
- delete fSubscribeContent;
- delete fShapeList;
-
- delete fLinkInfo.kind;
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::Subscribe
- //
- // Description: Set our shapes subscriber to this, adjust the counts so
- // that this link will be selected and unselected when it should be. Add to part
- // content model.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::Subscribe(Environment* ev)
- {
- // This does nothing when a link is created from PasteAs, as the list starts out empty
- // When the link itself is internalized due to paste or drop, this is where its shapes
- // get wired up to it.
-
- COrdListIterator shapeIter(fShapeList);
- for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
- {
- shape->Subscribe(ev, this);
- if (shape->IsSelected())
- ++fSelectedCount;
- }
-
- if (fSelectedCount != 0)
- {
- fSelection->IncrementPartialSubscribeCount(1);
- if (fSelectedCount == fShapeList->Count())
- fSelection->AddSubscribeLink(this);
-
- }
-
- this->AddToPart(ev);
-
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::PostCloneInternalizeLink
- //
- // Description: Complete the internalization process after cloning is done
- //-----------------------------------------------------------------------------
-
- ODBoolean CSubscribeLink::PostCloneInternalizeLink(Environment* ev, ODDraft* toDraft, CShape* shape)
- {
- ODBoolean result = kODTrue;
-
- // for the case of a single embedded part, a shape object was not created until
- // after cloning was done, so we had to defer attatching it to any links.
-
- if (shape)
- {
- this->AddShape(shape);
- }
-
-
- if (fODLink == kODNULL)
- {
- result = toDraft->IsValidID(ev, fODID);
-
- if (result)
- fODLink = toDraft->AcquireLink(ev, fODID, kODNULL);
- }
-
-
- if (result)
- {
- // We don't call Subscribe here because wan't to defer calling AddToPart, which is called from there.
-
- // The problem is that for an automatic link, that can precipitate a synchronous call
- // to LinkUpdated, when the part is registered. That currently blows away the current
- // selection. If 'this' is the content of the selection that leaves things in kind of a
- // mess. Instead, the caller has to copy fSubscribeLinks (CPasteCommand and CDropCommand
- // will anyway, for undo reasons), and then iterate the copied list to add the links to
- // the part after internalization is all done.
-
- // The case where this could happen is if a destination was copied, the source then modified
- // the destination then pasted. This would cause the pasted new destiantion to update immeditately
-
- // However, we do have to 'subscribe' all our internalized shapes so that any publishers that enclose
- // this link will behave correctly with respect to those shapes and this subscribe link.
-
- COrdListIterator shapeIter(fShapeList);
- for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
- {
- shape->Subscribe(ev, this);
-
- // When the shapes were added, they were not yet part of the selection, even if it was
- // the Selection content that was internalizing. If the shapes were added to the selection
- // then it was before they pointed to this subscribe link. The link itself is already in
- // the appropriate content list, so we just need to update fSelectedCount
-
- if (shape->IsSelected())
- ++fSelectedCount;
- }
- }
-
- return result;
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::Unsubscribe
- //
- // Description: Remove from part, adjust selection, clear refernces in
- // contained shapes. Inverse operation of Subscribe.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::Unsubscribe(Environment* ev)
- {
- CShape* shape;
-
- // before we mess anything up, we need to see if this link is part of
- // a clipboard promise. This would be true iff all our content is
- // in a clipboard promise.
- ODBoolean promised = kODTrue;
-
- COrdListIterator ite(fShapeList);
- for (shape = (CShape*)ite.First(); ite.IsNotComplete(); shape = (CShape*)ite.Next())
- {
- if (!shape->IsPromisedToClipboard())
- {
- promised = kODFalse;
- break;
- }
- }
-
- if (promised)
- ::ResolveClipboardPromises(ev, fDrawEditor->GetSession(ev));
-
- this->RemoveFromPart(ev, kODFalse); // Remove this from the part, but don't remove any shapes!
-
- if (fSelectedCount == fShapeList->Count())
- {
- fSelection->RemoveSubscribeLink(this);
- }
-
- if (fSelectedCount != 0)
- {
- fSelection->IncrementPartialSubscribeCount(-1);
- fSelectedCount = 0;
- }
-
- COrdListIterator shapeIter(fShapeList);
- for (shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
- {
- shape->Unsubscribe(ev);
- }
-
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::Publish
- //
- // Description: This is called for each contained destination link by a publisher
- // when it is 'published'.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::Publish(Environment* ev, CPublishLink* publishLink)
- {
-
- fPublishLinks->AddLast(publishLink);
-
-
- COrdListIterator shapeIter(fShapeList);
- for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
- {
- // Don't call AddShape(ev,shape), because it calls shape->Publish. A subscribed shape need only
- // point to its subsribe link and an embedded frame already has status kODInLinkDestination, which
- // takes precedence over kODInLinkSource.
-
- // This just adds the shape to the publisher's shape list. When a source link is first published
- // it has a list consisting of only it's non-subscribed shapes and a list of subscribers, then it
- // get's the rest of the shapes by Publishing it's subscribers.
-
- publishLink->AddShape(shape);
-
- }
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::Unpublish
- //
- // Description: Remove the indicated CPublishLink from our list of publishers
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::Unpublish(Environment* ev, CPublishLink* publishLink)
- {
- fPublishLinks->Remove(publishLink);
-
- // no need to do anything with our shapes, they're still subscribed, and are not
- // directly affected by the change in status.
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::AddToPart
- //
- // Description: Add this link to the part's content model. If this removed
- // shapes from the content model when RemoveFromPart was called, then add them
- // back as well. Adjust part's registration for update notification.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::AddToPart(Environment *ev)
- {
- fDrawEditor->AddSubscribeLink(this);
-
- if (fRemovedShapes)
- {
- // Add my shapes to the part
- COrdListIterator iter(fShapeList);
- for (CShape* shape = (CShape*)iter.First();
- iter.IsNotComplete();
- shape = (CShape*)iter.Next())
- {
- fDrawEditor->AddShape(ev, shape);
- }
-
- fRemovedShapes = kODFalse;
- }
-
- fWasRemoved = kODFalse;
- this->Register(ev);
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::RemoveFromPart
- //
- // Description: Remove this from the part's content model, if indicated
- // remove contained shapes from the part as well. Adjust part's registration
- // for update notification.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::RemoveFromPart(Environment* ev, ODBoolean doRemoveShapes)
- {
- fDrawEditor->RemoveSubscribeLink(this);
-
- fWasRemoved = kODTrue;
-
- // Remove my shapes from the part: When undoing a paste, or redoing a cut or clear,
- // It's possible that the shapes that were in the link originally were replaced by
- // link updates. So the responsiblility for removing its shapes is delegated to the
- // link itself.
-
- if (doRemoveShapes)
- {
- fRemovedShapes = kODTrue;
-
- COrdListIterator iter(fShapeList);
- for (CShape* shape = (CShape*)iter.First();
- iter.IsNotComplete();
- shape = (CShape*)iter.Next())
- {
- if (shape->IsSelected())
- fSelection->RemoveFromSelection(ev, shape, kODFalse);
-
- fDrawEditor->RemoveShape(ev, shape);
- }
- }
-
- this->Unregister(ev);
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::Register
- //
- // Description: Make sure that the part is registered with the ODLink for
- // automatic update notification if appropriate.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::Register(Environment* ev)
- {
-
- if (fRegistered) return;
- if (!fODLink) return; // link hasn't finished being internalized yet!
-
- ODUpdateID odID = fODLink->GetUpdateID(ev);
- ODBoolean needsUpdate = (fLinkInfo.change != odID);
-
- // If it's an automatic, OR if it's never been updated, then register for an automatic update
- // The later case is for creating a cross document link. The actual link won't be created
- // til after the paste or drop has completed, so we have to register for an update at that time.
- // simply calling LinkUpdated (as per DR3 recipe) now won't get us any content in that case.
- // Once the first real update has been received, LinkUpdated will 'Unregister' any non-automatic
- // links that were registered here.
-
- if (fLinkInfo.autoUpdate || (fShapeList->Count() == 0))
- {
- //--- Register for automatic updates ---
- // First determine if another subscriber with the same ODLink as ours already registered
-
- ODBoolean alreadyRegistered = kODFalse;
- COrdListIterator iter(fDrawEditor->GetSubscribeLinks());
- for (CSubscribeLink* subscriber = (CSubscribeLink*)iter.First(); iter.IsNotComplete(); subscriber = (CSubscribeLink*)iter.Next())
- {
- if ((subscriber != this) && fODLink->IsEqualTo(ev, subscriber->GetODLink())
- && subscriber->IsRegistered())
- {
- alreadyRegistered = TRUE;
- break;
- }
- }
-
- // before registering, set our flag, so the update that may come during RegisterDependent
- // will recognize this as an object requireing an automated update.
-
- fRegistered = TRUE;
-
- if (!alreadyRegistered)
- {
- fODLink->RegisterDependent(ev, fDrawEditor->GetODPart(), fLinkInfo.change);
- // part::LinkUpdated call will be generated if necessary
- needsUpdate = kODFalse;
- }
- }
-
- // Now that even a manual link is registered for the first instance, this only happens
- // when we're registering a link for which a previously registered subscriber existed in
- // this part.
-
- if (needsUpdate)
- {
- TRY
- this->LinkUpdated(ev, odID);
- CATCH_ALL
- // Theory is that the only error we care about is kODErrCannotEstablishLink
- // and that should only happen during ODPart::LinkUpdated, but don't propagate
- // update if LinkUpdated failed.
-
- return;
- ENDTRY
-
- fDrawEditor->ContentUpdated(ev, odID);
- fDrawEditor->SetDirty(ev);
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::Unregister
- //
- // Description: Unregister the part from the ODLink if appropriate.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::Unregister(Environment* ev)
- {
- if (!fRegistered) return;
-
- if (fLinkInfo.autoUpdate || (fShapeList->Count() == 0))
- {
- //--- Unregister for automatic updates ---
- // First determine if another subscriber with the same ODLink as ours is still registered
-
- ODBoolean lastOne = kODTrue;
-
- COrdListIterator iter(fDrawEditor->GetSubscribeLinks());
- for (CSubscribeLink* subscriber = (CSubscribeLink*)iter.First(); iter.IsNotComplete(); subscriber = (CSubscribeLink*)iter.Next())
- {
- if ((subscriber != this) && fODLink->IsEqualTo(ev, subscriber->GetODLink())
- && subscriber->IsRegistered())
- {
- lastOne = kODFalse;
- break;
- }
- }
-
- if (lastOne) // this is the only registered link
- {
- fODLink->UnregisterDependent(ev, fDrawEditor->GetODPart());
- }
- }
-
- fRegistered = kODFalse;
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::LinkUpdated
- //
- // Description: Handle the notification that updated content is available or
- // respond to a user's request to update a manual link.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::LinkUpdated(Environment* ev, ODUpdateID id)
- {
-
- ODLinkKey key;
- ODLink *link = this->GetODLink();
-
- if (link->Lock(ev, 0, &key))
- {
-
- ODStorageUnit* su = kODNULL;
- ODVolatile(su);
-
- TRY
-
- su = link->GetContentStorageUnit(ev, key);
-
- CATCH(kODErrCannotEstablishLink)
- link->Unlock(ev, key);
-
- if (fCommand)
- {
- fCommand->AbortLink(ev);
- fCommand = kODNULL;
- }
-
- RERAISE;
- CATCH_ALL
- link->Unlock(ev, key);
- RERAISE; // Allow callers to prevent propagating ContentUpdated to frame if we failed.
- ENDTRY
-
- // Deal with the asychronous creation of x document link sources. The above call fails
- // On the first (synchronous) update with an x doc link. The rest of the code won't execute until the
- // source link has actually been created and sent real data.
-
- // All links were initially registered even if manual until the first update is received.
- // correct the inconsistancy if it exists.
- if(!fLinkInfo.autoUpdate && fRegistered)
- this->Unregister(ev);
-
- // For a copy/paste-as created link, we've waited for the first update to create a kODEndAction
- if (fCommand)
- {
- fCommand->CompleteLink(ev);
- fCommand = kODNULL;
- }
-
- // We're going to use the selection because it knows how to move stuff and we want to be able
- // to move the new content to where the old content was
-
- // First take a snapshot of the selection so we can restore it after we're done
-
- COrderedList tempShapeList;
- COrdListIterator iter(fSelection->GetShapeList());
- for (CShape* shape = (CShape*)iter.First();
- iter.IsNotComplete();
- shape = (CShape*)iter.Next())
- {
- // Don't list any of this link's shapes, cuz they're about to get blown away
- if (shape->GetSubscribeLink() != this)
- tempShapeList.AddLast(shape);
- }
-
- // Need to know whether the new shapes should remain selected when the update is done.
- ODBoolean thisLinkWasSelected = fSelectedCount == fShapeList->Count();
-
- // Now close the selection
- fSelection->CloseSelection(ev);
-
- ODPoint newPosition(50, 50); // default location for first update. Same as for paste.
- ODBoolean first = kODTrue;
-
- // Out with the Old
-
- while (fShapeList->Count() != 0)
- {
- CShape *shape = (CShape*)fShapeList->RemoveFirst();
-
- ODRect shapeRect;
- shape->GetBoundingBox(&shapeRect);
-
- if (first || shapeRect.left < fOriginPoint.x)
- fOriginPoint.x = shapeRect.left;
- if (first || shapeRect.top < fOriginPoint.y)
- fOriginPoint.y = shapeRect.top;
-
- first = kODFalse;
-
- // Not necessary since we are closing the selection first, but if we change
- // and do this without closing the selection then we need to do this.
- if (shape->IsSelected())
- fSelection->RemoveFromSelection(ev, shape, kODFalse);
-
- fDrawEditor->RemoveShape(ev, shape);
-
- shape->SetInLimbo(ev, kODTrue);
- shape->Removed(ev, kODTrue);
-
- // Resolve any promises for shapes that are about to be blown away.
- // Note that this will only happen once, as the rest of the shapes
- // will no longer be promised after the first time.
- if (shape->IsPromisedToClipboard())
- {
- ::ResolveClipboardPromises(ev, fDrawEditor->GetSession(ev));
- }
-
- delete shape;
- }
-
- // In with the new
-
- ODFrame* frame = kODNULL;
- ODVolatile(frame);
-
- TRY
- frame = fDrawEditor->GetFirstSourceFrame(ev);
- CCloneInfo cloneInfo(0, su->GetDraft(ev), frame, kODCloneFromLink);
-
- // If the user's choice in PasteAs was different from the default for the original link content
- // then force the updated content to be internalized in the chosen way
-
- // User chose to embed intrinsic content in a frame.
- if (!fPasteAsResult.mergeSetting && fDefaultIsMerge)
- fSubscribeContent->HandleTranslateContent(ev, su, &cloneInfo, kODTrue);
-
- // User chose to merge a single embedded DrawEditor frame.
- else if (fPasteAsResult.mergeSetting && !fDefaultIsMerge)
- fSubscribeContent->HandleTranslateContent(ev, su, &cloneInfo, kODFalse);
-
- // Otherwise, the user's choice in PasteAs was the same as the default for the original content,
- // so internalize the current content in the default way.
-
- else
- fSubscribeContent->HandleInternalizeContent(ev, su, &cloneInfo);
-
- link->Unlock(ev, key);
-
- CATCH_ALL
- link->Unlock(ev, key);
-
- // A cool thing to do: Cache the old shapes before attempting to internalize.
- // restore them to the link and the part here, or delete them below if internalization
- // succeeds.
-
- RERAISE; // Allow callers to prevent propagating ContentUpdated to frame if we failed.
- ENDTRY
-
- // Adjust positioning of new content
-
- // First select our new content
- this->AddToSelection(ev, kODFalse);
-
-
- ODRect box;
- fSelection->GetSelectionRectangle(&box);
-
- fSelection->OffsetSelection(ev,
- frame,
- fOriginPoint.x - box.left,
- fOriginPoint.y - box.top);
-
- fLinkInfo.change = id;
- fLinkInfo.changeTime = this->GetODLink()->GetChangeTime(ev);
-
- // Restore the selection to it's original content
-
- // if this link was only partially selected, we don't know which of our shapes to leave selected
- // because there's no 1-1 correspondence between the old shapes and the replacement shapes, so
- // just close the selection.
-
- if (!thisLinkWasSelected)
- fSelection->CloseSelection(ev);
-
- // Add the selected shapes that were not affected by this update back into the selection.
- while (tempShapeList.Count() != 0)
- {
- CShape* shape = (CShape*)tempShapeList.RemoveFirst();
- fSelection->AddToSelection(ev, shape, kODFalse);
- }
-
-
- // Here's where we propagate changes to any sources which contain this destination.
- // Since sources always contain whole destinations, every object in the destination
- // has exactly the same publishers, so we keep them here (in the subscribe link) rather than dealing with each
- // contained shape.
-
- COrdListIterator iter2(fPublishLinks);
- for (CPublishLink* link = (CPublishLink*)iter2.First(); iter2.IsNotComplete(); link = (CPublishLink*)iter2.Next())
- {
- link->ContentUpdated(ev, id);
- }
-
- // Don't call DrawEditor::ContentUpdated here, because we could be updating multiple
- // CSubscribeLinks from the same notification with the same updateID.
- // DrawEditor::LinkUpdated does it once after the entire update is complete.
-
-
- }
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::AddShape
- //
- // Description: Add a shape to this subscribe link and add it to any publishers
- // it is contained in.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::AddShape(CShape* shape)
- {
- // Shapes are normally added to a subscribe link when it or it is internalized from a storage unit
- // When shapes are removed from and added to the part, all the shapes
- // within a CSubscribeLink are added and removed together, but are left
- // in the fShapeList list.
-
- if (!fWasRemoved)
- {
- fShapeList->AddLast(shape);
- if (shape->IsSelected())
- fSelectedCount++;
- }
-
- COrdListIterator ite(fPublishLinks);
- for (CPublishLink* plink = (CPublishLink*)ite.First(); ite.IsNotComplete(); plink = (CPublishLink*)ite.Next())
- plink->AddShape(shape);
-
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::AddShape
- //
- // Description: This method is called when a newly internalize shape is added to a link.
- // In this case, the shapes were added to the part, but had no subscriber pointers at
- // the time. Now we have make the shape a subscriber and then add it to our content.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::AddShape(Environment* ev, CShape* shape)
- {
-
- // now make it a subscriber
- shape->Subscribe(ev, this);
-
- // now our ordinary AddShape method that wasn't called when the shape was added to the part
- this->AddShape(shape);
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::RemoveShape
- //
- // Description: If the link was not removed from the part, then remove the
- // shape from this link and remove it from any link sources this is contained in.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::RemoveShape(CShape* shape)
- {
- // Shapes are normally removed from a subscribe link when it updates.
- // When shapes are removed from he part, all the shapes
- // within a CSubscribeLink are added and removed together, but are left
- // in the fShapeList list.
-
- if (!fWasRemoved)
- {
- fShapeList->Remove(shape);
- if (shape->IsSelected())
- fSelectedCount--;
- }
-
- COrdListIterator ite(fPublishLinks);
- for (CPublishLink* plink = (CPublishLink*)ite.First(); ite.IsNotComplete(); plink = (CPublishLink*)ite.Next())
- plink->RemoveShape(shape);
-
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::ShapeSelected
- //
- // Description: Keep track of how many of of our shapes have been selected
- // and inform the selection when it's count of partially selected links and/or
- // it's list of fully selected links needs to be updated.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::ShapeSelected(ODBoolean selectState)
- {
- short oldCount = fSelectedCount;
-
- if (selectState)
- {
- ++fSelectedCount;
- ASSERT(fSelectedCount <= fShapeList->Count(), kODErrAssertionFailed);
-
- if (oldCount == 0)
- {
- fSelection->IncrementPartialSubscribeCount(1);
- }
-
- if (fSelectedCount == fShapeList->Count())
- {
- fSelection->AddSubscribeLink(this);
- }
- }
- else
- {
- --fSelectedCount;
- ASSERT(fSelectedCount >= 0, kODErrAssertionFailed);
-
- if (oldCount == fShapeList->Count())
- {
- fSelection->RemoveSubscribeLink(this);
- }
-
- if (fSelectedCount == 0)
- {
- fSelection->IncrementPartialSubscribeCount(-1);
- }
- }
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::AddToSelection
- //
- // Description: Add our shapes to the selection. Used to select subscribed
- // shapes when undoing or redoing certain commands.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::AddToSelection(Environment* ev, ODBoolean drawHandles)
- {
- COrdListIterator iter(fShapeList);
- for (CShape* shape = (CShape*)iter.First();
- iter.IsNotComplete();
- shape = (CShape*)iter.Next())
- {
- fSelection->AddToSelection(ev, shape, drawHandles);
- }
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::RemoveShapes
- //
- // Description: When committing a command in a state in which the shapes are
- // removed from the content, handle the removal and deletion of contained shapes.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::RemoveShapes(Environment* ev, ODBoolean commit)
- {
-
- // This is only called when commiting removal of shapes and link
- ASSERT(commit == kODTrue, kODErrAssertionFailed);
-
- while (fSubscribeContent->Count() != 0)
- {
- CShape* shape = (CShape*)fShapeList->First();
-
- // We're going to blow the shape away. Don't want dangling pointers used
- // later to fulfill a promise. In case fulfilling the promise also causes this link
- // to be externalized, then all of our shapes are promised, and ResolveClipboardPromises will happen on
- // the first shape. However, due to that case, it must happen before we actually remove
- // any shapes from our shape list, otherwise the link won't externalize properly.
-
- if (shape->IsPromisedToClipboard())
- {
- ::ResolveClipboardPromises(ev, fDrawEditor->GetSession(ev));
- }
-
- fShapeList->RemoveFirst();
-
- shape->SetInLimbo(ev, kODTrue);
- shape->Removed(ev, kODTrue);
- delete shape;
- }
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::ExternalizeLink
- //
- // Description: Externalize the ODLink and the data defining this link.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::ExternalizeLink(Environment *ev, ODStorageUnit* su, CCloneInfo* cloneInfo)
- {
- ODID linkDestID = this->GetODLink()->GetID(ev);
- ODBoolean valid = kODTrue;
-
- if (cloneInfo)
- {
- linkDestID = cloneInfo->fFromDraft->Clone(ev, cloneInfo->fKey, linkDestID, kODNULLID, kODNULLID);
- valid = cloneInfo->fFromDraft->IsValidID(ev, linkDestID);
- }
-
- if (valid)
- {
-
- // store the number of shapes
- ODUShort shapeCnt = fShapeList->Count();
-
- StorageUnitSetValue(su, ev, sizeof(ODUShort), &shapeCnt);
-
- // store a reference to the link
- ODStorageUnitRef aSURef ;
- su->GetStrongStorageUnitRef(ev, linkDestID, aSURef);
- StorageUnitSetValue(su, ev, kODStorageUnitRefSize, &aSURef);
-
- // store the link info
- StorageUnitSetValue(su, ev, sizeof(ODLinkInfo), &fLinkInfo);
-
- // link info has a string in it, we need to store that too.
- StorageUnitSetISOStrValue( su, ev, fLinkInfo.kind);
-
- // store pasteAsResult
- StorageUnitSetValue(su, ev, sizeof(ODPasteAsResult), &fPasteAsResult);
-
- // We don't preserve the selectedKind and translateKind strings in fPaResult
- // (the selectedKind is 'given' to fLinkInfo.kind, and the translationKind
- // was ditched after the link was initially created from pasteAs.
-
- // store the default merge setting
- StorageUnitSetValue(su, ev, sizeof(ODBoolean), &fDefaultIsMerge);
-
-
- // store the export indices for each shape in the link.
- COrdListIterator iter(fShapeList);
- for (CShape *shape = (CShape*)iter.First(); iter.IsNotComplete(); shape = (CShape*)iter.Next())
- {
- ODUShort extInd = shape->GetExternalizationIndex();
- StorageUnitSetValue(su, ev, sizeof(ODUShort), &extInd);
- }
- }
- else
- {
- ODUShort invalShapeCnt = 0;
- StorageUnitSetValue(su, ev, sizeof(ODUShort), &invalShapeCnt);
- }
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::InternalizeLink
- //
- // Description: Internalize an ODLink and the necessary associated data
- //-----------------------------------------------------------------------------
-
- ODBoolean CSubscribeLink::InternalizeLink( Environment *ev, ODStorageUnit *su, CCloneInfo *cloneInfo, CShape** shapeTable)
- {
- ODUShort count;
- StorageUnitGetValue(su, ev, sizeof(ODUShort), &count);
-
- if (count == 0) // link was invalid from the git go
- return kODFalse;
-
- ODBoolean validLink = kODTrue;
- ODVolatile(validLink);
-
- TRY
-
- ODStorageUnitRef aSURef;
- StorageUnitGetValue(su, ev, kODStorageUnitRefSize, &aSURef);
-
- validLink = su->IsValidStorageUnitRef(ev, aSURef) ;
-
- StorageUnitGetValue(su, ev, sizeof(ODLinkInfo), &fLinkInfo);
- fLinkInfo.kind = StorageUnitGetISOStrValue(su, ev);
-
- StorageUnitGetValue(su, ev, sizeof(ODPasteAsResult), &fPasteAsResult);
-
- // We didn't externalize the selectedKind and translateKind strings in fPaResult
-
- StorageUnitGetValue(su, ev, sizeof(ODBoolean), &fDefaultIsMerge);
-
- if (validLink )
- {
- // we have a validated su ref for the link, so clone and get the link
- fODID = su->GetIDFromStorageUnitRef(ev, aSURef);
-
- if (cloneInfo)
- fODID = cloneInfo->fFromDraft->Clone(ev, cloneInfo->fKey, fODID, kODNULLID, kODNULLID);
- }
-
- for (ODUShort k = 0; k < count; k++)
- {
- ODUShort intIndex;
- StorageUnitGetValue(su, ev, sizeof(short), &intIndex);
-
- if(validLink && (shapeTable != kODNULL))
- {
- CShape *shape = shapeTable[intIndex];
- this->AddShape(shape);
- }
- }
-
- CATCH_ALL
- validLink = kODFalse;
- ENDTRY
-
- return validLink;
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::ShowCantEditDialog
- //
- // Description: Show the appropriate 'Can't Edit' dialog for a single
- // link which prevents a content modification.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::ShowCantEditDialog(Environment* ev)
- {
- // Temporary until the HI specified dialog is implemented:
- // The LinkInfo dialog does all the required things, just doesn't show the 'Can't Edit' text.
-
- this->ShowLinkInfoDialog(ev);
- }
-
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::ShowLinkInfoDialog
- //
- // Description: Show the Link Destination Info dialog for this link,and respond
- // to the user's choices.
- //-----------------------------------------------------------------------------
-
- void CSubscribeLink::ShowLinkInfoDialog(Environment* ev)
- {
-
- ODLinkInfoResult infoResult;
-
- // Get a facet to pass to ShowLinkDestinationInfo
- TempODFrameFacetIterator facets(ev,fDrawEditor->GetFirstSourceFrame(ev));
-
- if ( this->GetODLink()->ShowLinkDestinationInfo(ev,
- facets.Current(),
- &fLinkInfo,
- !fDrawEditor->IsReadOnly(),
- &infoResult) )
- {
- switch (infoResult.action)
- {
- case kODLinkInfoFindSource:
- this->GetODLink()->ShowSourceContent(ev);
- break;
- case kODLinkInfoBreakLink:
- CBreakLinkCommand* command = new CBreakLinkCommand(fDrawEditor, this);
- fDrawEditor->ExecuteCommand(ev, command);
- break;
- case kODLinkInfoUpdateNow:
-
- // Update now button should have been disabled if our info indicated that we're already up to
- // up to date.
-
- // For a manual update, we don't re-use the existing updateID, but generate a new one.
- // The reason for propagating the same ID for automatic updates is to prevent runaway
- // recursion. For a manual update, using the same ID as our last update could preciptate
- // link cycle dialog when the id is passed to any local or containing publishers. The user
- // in choosing to update manually, does not need to be further queried.
-
- ODUpdateID updateID = fDrawEditor->GetSession(ev)->UniqueUpdateID(ev);
-
- TRY
- this->LinkUpdated(ev, updateID);
-
- CATCH_ALL
- // Theory is that the only error we care about is kODErrCannotEstablishLink
- // and that should only happen during ODPart::LinkUpdated, but skip propagating
- // changes if update failed.
-
- break;
- ENDTRY
-
-
- // store the actual update id from the link so the 'Update Now' button won't be
- // enabled the next time unless the link actually changed.
-
- fLinkInfo.change = this->GetODLink()->GetUpdateID(ev);
-
- fDrawEditor->ContentUpdated(ev,updateID);
- fDrawEditor->SetDirty(ev);
- break;
-
- case kODLinkInfoOk:
- if (infoResult.autoUpdate != fLinkInfo.autoUpdate)
- {
- fLinkInfo.autoUpdate = infoResult.autoUpdate;
- if (infoResult.autoUpdate)
- this->Register(ev); // Will precipitate the necessary update
- else
- this->Unregister(ev);
- }
- break;
-
- default:
- break;
- }
- }
-
-
- }
-
- //-----------------------------------------------------------------------------
- // CSubscribeLink::Count
- //
- // Description: How many shapes?
- //-----------------------------------------------------------------------------
- ODULong CSubscribeLink::Count()
- {
- return fShapeList->Count();
- }
-
-